#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 2e5 + 10; // 最大范围
vector<bool> isNotPrime(MAXN, false); // 标记是否为合数
vector<int> primes; // 存储素数
vector<int> value; // 存储节点的权值
vector<vector<int>> next; // 邻接表存储树结构
int res = 0; // 结果，记录最多可以染红的节点数

// 欧拉筛法，预处理素数
void sieve() {
    for (int i = 2; i < MAXN; ++i) {
        if (!isNotPrime[i]) {
            primes.push_back(i); // i 是素数
        }
        for (int prime : primes) {
            if (i * prime >= MAXN) break; // 超出范围
            isNotPrime[i * prime] = true; // 标记合数
            if (i % prime == 0) break; // 保证每个合数只被最小质因数标记
        }
    }
}

// DFS 遍历树
void dfs(int cur, int pre) {
	extern vector<vector<int>> next;
    for (int nxt : next[cur]) {
        if (nxt == pre) continue; // 防止回溯到父节点
        dfs(nxt, cur); // 递归遍历子节点

        int sum = value[cur] + value[nxt]; // 计算当前节点和子节点的权值和
        if (!isNotPrime[sum]) { // 如果和是质数
            res++; // 染红一个节点
        }
    }
}

int main() {
	extern vector<vector<int>> next;
	
    // 预处理素数
    sieve();

    int n;
    cin >> n;

    value.resize(n + 1);
    next.resize(n + 1);

    // 读取节点权值
    for (int i = 1; i <= n; ++i) {
        cin >> value[i];
    }

    // 建树
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        next[u].push_back(v);
        next[v].push_back(u);
    }

    // 从根节点 1 开始 DFS
    dfs(1, -1);

    // 输出结果
    cout << res << endl;

    return 0;
}